use axum::{middleware, Router};
use tower_cookies::CookieManagerLayer;
use tower_http::services::ServeDir;
use tower_http::trace::TraceLayer;
use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};
use std::env;

mod core;
mod types;
mod model;
mod services;
mod controllers;
mod router;

#[tokio::main]
async fn main() {
    dotenv::dotenv().ok();
    // read env variables
    let db_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
    let host = env::var("HOST").expect("HOST must be set");
    let port = env::var("PORT").expect("PORT must be set");
    let server_url = format!("{}:{}", host, port);

    // 日志跟踪
    tracing_subscriber::registry()
        .with(tracing_subscriber::fmt::layer())
        .init();

    // 初始化数据库连接池
    let db = core::psqlx::get_pool(&db_url).await;

    // state
    let state = core::AppState {
        db,
    }; 

    // session
    let backend_session_layer = core::xsession::init_session().await.expect("session 初始化失败");

    let app = Router::new()
        .nest("/", router::frontend::frontend_router())
        .nest(
            "/backend", 
            router::backend::backend_router()
            .layer(middleware::from_fn(core::auth_middleware::auth_middleware))
            .layer(CookieManagerLayer::new())
            .layer(backend_session_layer)
        )
        .nest_service("/assets", ServeDir::new("assets"))
        .nest_service("/upload", ServeDir::new("upload"))
        .layer(TraceLayer::new_for_http())
        .with_state(state);


    let listener = tokio::net::TcpListener::bind(server_url).await.unwrap();
    axum::serve(listener, app).await.unwrap();
}
